Skip to content

cherry-pick(4.3-stable): guard preserveMountedTags against resolveView throwing (#9649)#9827

Merged
MatiPl01 merged 1 commit into
4.3-stablefrom
@matipl01/4.3-stable/cherry-pick-#9649
Jul 2, 2026
Merged

cherry-pick(4.3-stable): guard preserveMountedTags against resolveView throwing (#9649)#9827
MatiPl01 merged 1 commit into
4.3-stablefrom
@matipl01/4.3-stable/cherry-pick-#9649

Conversation

@MatiPl01

@MatiPl01 MatiPl01 commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

Cherry-picking for Reanimated 4.3.2 release

Cherry-pick notes

4.3-stable still has the Java NativeProxy.java (the Kotlin migration landed after 4.3 branched), so the same try/catch guard around resolveView was applied to the Java preserveMountedTags instead of NativeProxy.kt.

…ng (#9649)

Fixes #9636.

`NativeProxy.preserveMountedTags` assumes `FabricUIManager.resolveView`
returns `null` for a tag whose view isn't mounted:

```kotlin
for (i in tags.indices) {
    if (mFabricUIManager.resolveView(tags[i]) == null) {
        tags[i] = -1
    }
}
```

In practice `resolveView` (→ `SurfaceMountingManager.getView`) **throws
`IllegalViewOperationException`** when the tag's `ViewState` is already
registered but the Android view object hasn't been created yet. That
uncaught throw on the main thread is fatal.

This is reachable when a view is **mid-preallocation** and a third-party
view manager dispatches an event **synchronously from inside
`createView`**, re-entering Reanimated's event path before the view
exists. `lottie-react-native` does exactly this: when a composition is
already in Lottie's in-memory cache, `setAnimation` fires
`onAnimationLoaded` synchronously during `createViewInstance`, which
dispatches through `FabricEventDispatcher` →
`NodesManager.onEventDispatch` → `performOperations` →
`preserveMountedTags` → `resolveView` on the tag that is still being
preallocated.

Observed crash:

```
com.facebook.react.uimanager.IllegalViewOperationException: Unable to find view for tag N. Surface 1 stopped: false, rootViewAttached: true
    at com.facebook.react.fabric.mounting.SurfaceMountingManager.getView
    at com.facebook.react.fabric.FabricUIManager.resolveView
    at com.swmansion.reanimated.NativeProxy.preserveMountedTags
    at com.swmansion.reanimated.NativeProxy.performOperations (Native Method)
    ...
    at com.airbnb.android.react.lottie.LottieAnimationViewManagerImpl.sendAnimationLoadedEvent
    at com.airbnb.lottie.LottieAnimationView.setComposition
    ...
    at com.facebook.react.fabric.mounting.SurfaceMountingManager.createViewUnsafe
    at com.facebook.react.fabric.mounting.SurfaceMountingManager.preallocateView
```

The fix wraps the `resolveView` call in a try/catch and treats
`IllegalViewOperationException` the same as the existing `null` branch —
the tag has no usable view yet, so mark it `-1`. This matches the intent
of the original null check (a tag without a mounted view is dropped) and
is the minimal hot-fix that eliminates the crash. As @bartlomiejbloniarz
noted in the issue, this path can eventually be removed once the pull
model lands on Android.

Minimal standalone Expo repro (crashes within ~1s of launch on Android,
New Architecture, before this change; no crash with it applied):

**https://github.com/audrius-savickas/lottie-reanimated-9636-repro**

```bash
npm install
npx expo run:android
```

It mounts several `Animated.createAnimatedComponent(LottieView)`
instances with `entering`/`exiting` and remounts them every 250 ms, with
the Lottie source bundled locally so the first remount is a guaranteed
cache hit (the synchronous `onAnimationLoaded` during preallocation).
Full captured trace is in
[`CRASH-STACKTRACE.txt`](https://github.com/audrius-savickas/lottie-reanimated-9636-repro/blob/main/CRASH-STACKTRACE.txt).

Versions matching the production crash: `react-native@0.85.3` (New
Arch), `react-native-reanimated@4.3.1`, `react-native-worklets@0.8.3`,
`lottie-react-native@7.3.4`.

Co-authored-by: audrius.sav <audrius.savickas@eneba.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 502cf70)
@MatiPl01 MatiPl01 merged commit 173d6ad into 4.3-stable Jul 2, 2026
15 checks passed
@MatiPl01 MatiPl01 deleted the @matipl01/4.3-stable/cherry-pick-#9649 branch July 2, 2026 10:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants